home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / delivery / deliver.tz / deliver / lock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-07  |  7.1 KB  |  392 lines

  1. /* $Header: lock.c,v 2.2 90/05/03 10:13:56 chip Exp $
  2.  *
  3.  * Mailbox locking.
  4.  * Local hacks for mailbox access should be grafted here.
  5.  *
  6.  * $Log:    lock.c,v $
  7.  * Revision 2.2  90/05/03  10:13:56  chip
  8.  * Really unlock file descriptors in fd_unlock().  (!)
  9.  * 
  10.  * Revision 2.1  89/06/09  12:25:30  network
  11.  * Update RCS revisions.
  12.  * 
  13.  * Revision 1.6  89/06/09  12:23:52  network
  14.  * Baseline for 2.0 release.
  15.  * 
  16.  */
  17.  
  18. #include "deliver.h"
  19.  
  20. /*
  21.  * Validate the locking configuration.
  22.  */
  23.  
  24. #if (defined(ML_FCNTL) + defined(ML_LOCKF) + defined(ML_LOCKING)) > 1
  25.   lose! "Only one of ML_FCNTL, ML_LOCKF and ML_LOCKING may be defined.";
  26. #endif
  27.  
  28. /*
  29.  * Support for the lockf() system call.
  30.  */
  31.  
  32. #ifdef ML_LOCKF
  33. #include <unistd.h>
  34. #define SIMPLE_LOCK "lockf"
  35. #define LOCKFD(fd, size)    lockf(fd, F_LOCK, size)
  36. #define UNLOCKFD(fd, size)  lockf(fd, F_ULOCK, size)
  37. #endif /* ML_LOCKF */
  38.  
  39. /*
  40.  * Setup for the locking() system call.
  41.  */
  42.  
  43. #ifdef ML_LOCKING
  44. #include <sys/locking.h>
  45. #define SIMPLE_LOCK "locking"
  46. #define LOCKFD(fd, size)    locking(fd, LK_LOCK, size)
  47. #define UNLOCKFD(fd, size)  locking(fd, LK_UNLCK, size)
  48. #endif
  49.  
  50. /*
  51.  * Local functions.
  52.  */
  53.  
  54. #ifdef ML_DOTLOCK
  55. static  char    *dotlock_name();
  56. #endif
  57. #ifdef ML_DOTMLK
  58. static  char    *dotmlk_name();
  59. #endif
  60.  
  61. /*----------------------------------------------------------------------
  62.  * Lock a mailbox by name.
  63.  *
  64.  * This code looks quite hairy with all the ifdefs.  In fact, the only
  65.  * somewhat strange thing here is that neither, either, or both of
  66.  * ML_DOTLOCK and ML_DOTMLK may be defined, and we have to allow for it.
  67.  */
  68.  
  69. int
  70. name_lock(name)
  71. char    *name;
  72. {
  73. #ifdef ML_DOTLOCK
  74.     char    *dotlock;
  75. #endif
  76. #ifdef ML_DOTMLK
  77.     char    *dotmlk;
  78. #endif
  79.  
  80. #ifdef ML_DOTLOCK
  81.     if ((dotlock = dotlock_name(name)) == NULL
  82.      || create_lockfile(dotlock) < 0)
  83.         return -1;
  84. #endif /* ML_DOTLOCK */
  85.  
  86. #ifdef ML_DOTMLK
  87.     if ((dotmlk = dotmlk_name(name)) == NULL
  88.      || create_lockfile(dotmlk) < 0)
  89.     {
  90. #ifdef ML_DOTLOCK
  91.         (void) remove_lockfile(dotlock); /* don't leave me hanging */
  92. #endif
  93.         return -1;
  94.     }
  95. #endif /* ML_DOTMLK */
  96.  
  97.     return 0;
  98. }
  99.  
  100. /*----------------------------------------------------------------------
  101.  * Unlock a mailbox by name.
  102.  */
  103.  
  104. int
  105. name_unlock(name)
  106. char    *name;
  107. {
  108.     int     ret = 0;
  109.  
  110. #ifdef ML_DOTLOCK
  111.     char    *dotlock;
  112. #endif
  113. #ifdef ML_DOTMLK
  114.     char    *dotmlk;
  115. #endif
  116.  
  117. #ifdef ML_DOTLOCK
  118.     if ((dotlock = dotlock_name(name)) == NULL
  119.      || remove_lockfile(dotlock) < 0)
  120.         ret = -1;
  121. #endif /* ML_DOTLOCK */
  122.  
  123. #ifdef ML_DOTMLK
  124.     if ((dotmlk = dotmlk_name(name)) == NULL
  125.      || remove_lockfile(dotmlk) < 0)
  126.         ret = -1;
  127. #endif /* ML_DOTMLK */
  128.  
  129.     return ret;
  130. }
  131.  
  132. /*----------------------------------------------------------------------
  133.  * Lock a file descriptor.
  134.  */
  135.  
  136. int
  137. fd_lock(fd)
  138. int     fd;
  139. {
  140. #ifdef ML_FCNTL
  141.     struct flock fl;
  142.  
  143.     fl.l_type = F_WRLCK;
  144.     fl.l_whence = 0;
  145.     fl.l_start = 0L;
  146.     fl.l_len = 0L;
  147.  
  148.     if (fcntl(fd, F_SETLKW, &fl) == -1)
  149.     {
  150.         syserr("can't lock with fcntl()");
  151.         return -1;
  152.     }
  153.  
  154.     if (verbose)
  155.         message("locked mailbox with fcntl()\n");
  156. #endif /* ML_FCNTL */
  157.  
  158. #ifdef SIMPLE_LOCK
  159.     long    pos;
  160.  
  161.     if ((pos = lseek(fd, 0L, 0)) == -1)
  162.     {
  163.         syserr("can't seek in mailbox");
  164.         return -1;
  165.     }
  166.     if (LOCKFD(fd, 0L) == -1)
  167.     {
  168.         syserr("can't lock with %s()", SIMPLE_LOCK);
  169.         return -1;
  170.     }
  171.     if (lseek(fd, pos, 0) == -1)
  172.     {
  173.         syserr("can't seek in mailbox");
  174.         return -1;
  175.     }
  176.  
  177.     if (verbose)
  178.         message("locked mailbox with %s()\n", SIMPLE_LOCK);
  179. #endif /* SIMPLE_LOCK */
  180.  
  181.     /* Default: success */
  182.     return 0;
  183. }
  184.  
  185. /*----------------------------------------------------------------------
  186.  * Unlock a file descriptor.
  187.  */
  188.  
  189. int
  190. fd_unlock(fd)
  191. int     fd;
  192. {
  193. #ifdef ML_FCNTL
  194.     struct flock fl;
  195.  
  196.     fl.l_type = F_UNLCK;
  197.     fl.l_whence = 0;
  198.     fl.l_start = 0L;
  199.     fl.l_len = 0L;
  200.  
  201.     if (fcntl(fd, F_SETLKW, &fl) == -1)
  202.     {
  203.         syserr("can't unlock with fcntl()");
  204.         return -1;
  205.     }
  206.  
  207.     if (verbose)
  208.         message("unlocked mailbox with fcntl()\n");
  209. #endif /* ML_FCNTL */
  210.  
  211. #ifdef SIMPLE_LOCK
  212.     long    pos;
  213.  
  214.     if ((pos = lseek(fd, 0L, 0)) == -1)
  215.     {
  216.         syserr("can't seek in mailbox");
  217.         return -1;
  218.     }
  219.     if (UNLOCKFD(fd, 0L) == -1)
  220.     {
  221.         syserr("can't unlock with %s()", SIMPLE_LOCK);
  222.         return -1;
  223.     }
  224.     if (lseek(fd, pos, 0) == -1)
  225.     {
  226.         syserr("can't seek in mailbox");
  227.         return -1;
  228.     }
  229.  
  230.     if (verbose)
  231.         message("unlocked mailbox with %s()\n", SIMPLE_LOCK);
  232. #endif /* SIMPLE_LOCK */
  233.  
  234.     /* Default: success */
  235.     return 0;
  236. }
  237.  
  238. /*----------------------------------------------------------------------
  239.  * Return the name of the appropriate ".lock" file for a mailbox.
  240.  */
  241.  
  242. #ifdef ML_DOTLOCK
  243.  
  244. static char *
  245. dotlock_name(name)
  246. char    *name;
  247. {
  248.     static char *lname = NULL;
  249.     static int lsize = 0;
  250.     char    *p;
  251.     int     n, i;
  252.  
  253.     n = strlen(name);
  254.     if (lsize < n + 8)
  255.     {
  256.         if (lname)
  257.             free(lname);
  258.         lsize = n + 32;
  259.         lname = zalloc(lsize);
  260.     }
  261.  
  262.     (void) strcpy(lname, name);
  263.  
  264.     /*
  265.      * We want as much of `basename.lock' as will fit in a string
  266.      * MAX_NAMESIZE long.
  267.      */
  268.     for (i = 0, p = basename(lname); (i < MAX_NAMESIZE - 5) && (*p); ++i)
  269.         ++p;
  270.     (void) strcpy(p, ".lock");
  271.  
  272.     return lname;
  273. }
  274.  
  275. #endif /* ML_DOTLOCK */
  276.  
  277. /*----------------------------------------------------------------------
  278.  * Return the name of the appropriate ".mlk" file for a mailbox.
  279.  */
  280.  
  281. #ifdef ML_DOTMLK
  282.  
  283. static char *
  284. dotmlk_name(name)
  285. char    *name;
  286. {
  287.     static char lname[MAX_NAMESIZE + 16];
  288.     char    *p, *d;
  289.     int     i;
  290.  
  291.     /*
  292.      * To explain the below:  If we ass_u_me that MAX_NAMESIZE is 14,
  293.      * then this code is like `printf(lname, "/tmp/%.10s.mlk", ...)'.
  294.      * In other words, we want as much of `basename.mlk' as will fit
  295.      * in a string MAX_NAMESIZE long.
  296.      */
  297.     d = lname;
  298.     for (p = "/tmp/"; *p; )
  299.         *d++ = *p++;
  300.     for (i = 0, p = basename(name); (i < MAX_NAMESIZE - 4) && (*p); ++i)
  301.         *d++ = *p++;
  302.     (void) strcpy(d, ".mlk");
  303.  
  304.     return lname;
  305. }
  306.  
  307. #endif /* ML_DOTMLK */
  308.  
  309. /*----------------------------------------------------------------------
  310.  * Create a lockfile.
  311.  */
  312.  
  313. int
  314. create_lockfile(name)
  315. char    *name;
  316. {
  317. #ifndef O_CREAT
  318.     char    *othername, *p;
  319. #endif
  320.     int     fd, tries;
  321.  
  322. #ifndef O_CREAT
  323.     othername = zalloc(strlen(name) + 20);  /* fudge (???) */
  324.     (void) strcpy(othername, name);
  325.     (void) sprintf(basename(othername), ".dl.%d", getpid());
  326.     if ((fd = creat(othername, 0)) == -1)
  327.     {
  328.         syserr("can't create %s", othername);
  329.         return -1;
  330.     }
  331.     (void) close(fd);
  332.     if (verbose)
  333.         message("created pre-lockfile %s\n", name);
  334. #endif
  335.  
  336.     for (tries = 0; tries < 10; ++tries)
  337.     {
  338.         if (tries)
  339.             snooze(3);
  340.  
  341. #ifdef O_CREAT
  342.  
  343.         if ((fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0)) >= 0)
  344.         {
  345.             (void) close(fd);
  346.             if (verbose)
  347.                 message("created lockfile %s\n", name);
  348.             return 0;
  349.         }
  350.  
  351. #else /* not O_CREAT */
  352.  
  353.         if (link(othername, name) == 0)
  354.         {
  355.             if (unlink(othername) == -1)
  356.                 syserr("can't remove %s", othername);
  357.             free(othername);
  358.             if (verbose)
  359.                 message("created lockfile %s\n", name);
  360.             return 0;
  361.         }
  362.  
  363. #endif /* not O_CREAT */
  364.  
  365.         if (verbose && (tries == 0))
  366.             message("Waiting to create %s\n", name);
  367.     }
  368.  
  369.     syserr("can't create lockfile %s", name);
  370.     return -1;
  371. }
  372.  
  373. /*----------------------------------------------------------------------
  374.  * Remove a lockfile.
  375.  */
  376.  
  377. int
  378. remove_lockfile(name)
  379. char    *name;
  380. {
  381.     if (unlink(name) == -1)
  382.     {
  383.         syserr("can't remove lockfile %s", name);
  384.         return -1;
  385.     }
  386.  
  387.     if (verbose)
  388.         message("removed lockfile %s\n", name);
  389.  
  390.     return 0;
  391. }
  392.